package com.zim.ta_service.base.sequence.generator;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.zim.ta_service.base.exception.BizMsgException;
import com.zim.ta_service.base.sequence.enums.RedisSeqBizType;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/**
 * Redis生成序列号
 * @author alabimofa
 */
public class RedisGenerator implements IGenerator {

    private static StringRedisTemplate stringRedisTemplate;

    private final String key;
    private final Long expireSeconds;
    private final String dateFormat;
    private final Integer padLeftLength;
	private final String displayFormat;

    public RedisGenerator(RedisSeqBizType type) {
        if (null == type) {
            throw new BizMsgException("Redis序列号生成，业务类型不能为空");
        }

        if (StringUtils.isBlank(type.getTimeConfig().getFormat())) {
            throw new BizMsgException("Redis序列号生成，时间配置不能为空");
        }

        if (null == type.getTimeConfig().getExpireSeconds() || type.getTimeConfig().getExpireSeconds() <= 0) {
            throw new BizMsgException("Redis序列号生成，失效秒数不能为空");
        }

        if (null == type.getPadLeftLength() || type.getPadLeftLength() <= 0) {
            throw new BizMsgException("Redis序列号生成，左补0的位数不能为空");
        }

        this.key = "seq:build:".concat(StrUtil.toString(type.ordinal())).concat(StrUtil.COLON);
        this.expireSeconds = type.getTimeConfig().getExpireSeconds();
        this.dateFormat = type.getTimeConfig().getFormat();
        this.padLeftLength = type.getPadLeftLength();
		this.displayFormat = type.getDisplayFormat();

        if (null == stringRedisTemplate) {
            stringRedisTemplate = SpringUtil.getBean(StringRedisTemplate.class);
        }
    }

    @Override
    public Long nextId() {
		String date = LocalDateTimeUtil.format(LocalDateTime.now(), dateFormat);
		Long seq = stringRedisTemplate.opsForValue().increment(key.concat(date), 1L);
        if (null == seq || seq <= 0) {
            throw new RuntimeException("Redis Sequence Long value get null");
        }
        return seq;
    }

    @Override
    public String nextIdString() {
        String date = LocalDateTimeUtil.format(LocalDateTime.now(), dateFormat);
        Long seq = stringRedisTemplate.opsForValue().increment(key.concat(date), 1L);
        stringRedisTemplate.expire(key.concat(date), expireSeconds, TimeUnit.SECONDS);
        if (null == seq) {
            throw new RuntimeException("Redis Sequence get null");
        }
		if (StrUtil.isNotBlank(displayFormat)) {
			HashMap<String, String> valueMap = new HashMap<>();
			valueMap.put("time", date);
			valueMap.put("seq", StringUtils.leftPad(seq.toString(), padLeftLength, '0'));
			return StrUtil.format(displayFormat, valueMap);
		}
        return date.concat(StringUtils.leftPad(seq.toString(), padLeftLength, '0'));
    }
}
